跳到主要内容

3.6-浏览器的存储

Create by fall on 04 Dec 2020 Recently revised in 23 Oct 2023

数据存储

cookie 数据始终在同源的 http 请求中携带(即使不需要),即 cookie 在浏览器和服务器间来回传递,因此,cookie 数据不能超过 4K,cookie 数据还有路径(path)的概念,可以限制cookie 只属于某个路径下

sessionStorage & localStorage

而 sessionStorage 和 localStorage 不会自动把数据发送给服务器,仅在本地保存,存储大小的限制,比 cookie 大得多,可以达到 5M 或更大。都保存在浏览器端、且同源,区别如下

  1. 数据有效期不同,sessionStorage:仅在当前浏览器窗口关闭之前有效;localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;cookie:只在设置的 cookie 过期时间之前有效,即使窗口关闭或浏览器关闭
  2. 作用域不同,sessionStorage 在不同的浏览器窗口中不共享,即使是同一个地址;localstorage 在所有同源窗口中都是共享的;cookie也是在所有同源窗口中都是共享的
  3. web Storage 支持事件通知机制,可以将数据更新的通知发送给监听者
  4. web Storage的 API 接口使用更方便

数据管理

惰性删除:保存数据的同时,也保存时间,下次访问时,如果过期,删除数据

定时删除:每隔一定时间进行删除,删除的同时,检查其它缓存是否过期,如果过期,也进行删除

indexDB

  • 键值对储存,IndexDB 内部采用对象仓库(object store)存放数据。其中包括 JavaScript 的对象。
  • 异步,操作不同于 localStorage 的同步,不会锁死浏览器,所以可以实现大量数据读写。
  • 支持事务,如果一部分操作失败,会直接退回到最初的状态,不存在只修改一部分数据的情况。
  • 同源限制,indexDB 收到同源限制,不能访问跨域的数据库。
  • 存储空间大,一般来讲在 250M 以上,甚至没有上限
  • 支持二进制储存,存储字符串,ArrayBuffer,Blob对象
  • 数据库:IDBDatabase 对象
  • 对象仓库:IDBObjectStore 对象
  • 索引: IDBIndex 对象
  • 事务: IDBTransaction 对象
  • 操作请求:IDBRequest 对象
  • 指针: IDBCursor 对象
  • 主键集合:IDBKeyRange 对象

打开&创建数据库

打开数据库(如果没有数据库会进行创建)

var request = new window.indexedDB.open(databaseName,version)

新建数据库时,默认版本为1

indexedDB.open()方法返回一个 IDBRequest 对象。这个对象通过三种事件errorsuccessupgradeneeded,处理打开数据库的操作结果。

事件控制

Error 事件(表示数据库打开失败)

request.onerror = function(event){
console.log("打开数据库错误")
}

success 事件(表示成功打开数据库)

request.onsuccess = function(event){
db = request.result;
console.log('数据库打开成功')
}

upgradeneeded 事件 (表示升级数据库事件,版本大于当前版本时执行)

request.onupgradeneeded = function (event){
db = event.target.result
console.log('升级数据库事件触发')
}

新增数据

通常在新建数据库以后,第一件事是新建对象仓库(即新建表)。

一般创建数据库后的操作都在版本更替中进行

新建表

var request = new window.indexedDB.open(dataBaseName,version)
// 只能在 onupgradeneeded 中新建表
request.onupgradeneeded = function (event){
// 最好的写法是先判断这张表格是否存在,如果不存在再新建
if(!db.objectStoreNames.contains('person')){
// 新建一个person表,主键设置为 id
var objectStore = db.createObjectStore('person',{keyPath:'id'})
// keyPath:"info.id",可以是更深层的数据作为主键
// 创建完表之后,添加索引
objectStore.createIndex('name', 'name', { unique: false });
objectStore.createIndex('email', 'email', { unique: true });
}
// db.createObjectStore({autoIncrement: true }) // 当不设置主键,可以设置为自增
}

创建索引

// 三个参数分别为索引名称、索引所在的属性、配置对象
objectStore.createIndex('name', 'name', { unique: false });
objectStore.createIndex('email', 'email', { unique: true });

所有传入数据库的数据都要包含主键,和必须传入的字符

添加数据

完整的添加数据的流程

var db = null
var request = window.indexedDB.open("toDoList", 2);// 打开&创建数据库
// 如果版本更新,首先触发更新数据库的流程
request.onupgradeneeded = function (e) {
db = e.target.result
if (!db.objectStoreNames.contains('person')) {
// 新建一个person表,主键设置为 id
var objectStore = db.createObjectStore('person', { keyPath: 'id' })
// keyPath:"info.id",可以是更深层的数据作为主键
// 创建索引
objectStore.createIndex('name', 'name', { unique: false });
objectStore.createIndex('email', 'email', { unique: true });
}
console.log('更新数据库成功');
};
// 在打开数据库成功后才能进行添加数据
request.onsuccess = function (e) {
console.log('打开数据库成功');
db = e.target.result
// 表示操作,只读,或者是读写
// transaction 对象,事务对象,用作读写,删除等一系列操作,可以得到IDBObjectStore对象
var requestTable = db.transaction(['person'], 'readwrite')
.objectStore('person') // 存储在 person 表内
.add({
id: 1, name: 'jkjk', age: 24, email: 'bofei@example.com'
});
// 本次写入成功
requestTable.onsuccess = function (event) {
console.log('数据写入成功');
};
// 本次写入失败
requestTable.onerror = function (event) {
console.log('数据写入失败');
}
};
request.onerror = function (e) {
console.log("打开数据库失败");
}

读取数据

// 打开数据库
var request = window.indexedDB.open('toDoList')
// 请求成功
request.onsuccess = function (e) {
var db = e.target.result
var transaction = db.transaction(['person']);
var objectStore = transaction.objectStore('person');
// 读取数据库,objectStore.get(主键的值)
var request = objectStore.get(1);
// 请求数据成功
request.onsuccess = function (event) {
if (request.result) {
console.log('Name: ' + request.result.name);
console.log('Age: ' + request.result.age);
console.log('Email: ' + request.result.email);
} else {
console.log('未获得数据记录');
}
};
// 请求数据失败
request.onerror = function (event) {
console.log('事务失败');
};
}

遍历数据

// 打开数据库
var request = window.indexedDB.open('toDoList')
// 请求成功
request.onsuccess = function (e) {
var db = e.target.result
var objectStore = db.transaction('person').objectStore('person');
objectStore.openCursor().onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
console.log('Id: ' + cursor.key);
console.log('Name: ' + cursor.value.name);
console.log('Age: ' + cursor.value.age);
console.log('Email: ' + cursor.value.email);
cursor.continue();
} else {
console.log('没有更多数据了!');
}
};
// 请求数据失败
request.onerror = function (event) {
console.log('事务失败');
};
}

更新数据

var request = window.indexedDB.open('toDoList')
// 请求成功
request.onsuccess = function (e) {
var db = e.target.result
var request = db.transaction(['person'], 'readwrite').objectStore('person')
.put({ id: 1, name: 'baibai', age: '99', email: 'junde@shuai.com' })
request.onerror = function (e) {
console.log('更改错误');
}
request.onsuccess = function (e) {
console.log('更改成功');
console.log(e);
}
// 请求数据失败
request.onerror = function (event) {
console.log('事务失败');
};
var db = e.target.result
var transaction = db.transaction(['person']);
var objectStore = transaction.objectStore('person');
// 读取数据库,objectStore.get(主键的值)
var request = objectStore.get(1);
// 请求数据成功
request.onsuccess = function (event) {
if (request.result) {
console.log('Name: ' + request.result.name);
console.log('Age: ' + request.result.age);
console.log('Email: ' + request.result.email);
} else {
console.log('未获得数据记录');
}
};
// 请求数据失败
request.onerror = function (event) {
console.log('事务失败');
};
}

删除数据


function remove() {
var request = db.transaction(['person'], 'readwrite')
.objectStore('person')
.delete(1);

request.onsuccess = function (event) {
console.log('数据删除成功');
};
}
remove();

建立索引

var transaction = db.transaction(['person'], 'readonly');
var store = transaction.objectStore('person');
var index = store.index('name');
var request = index.get('李四');

request.onsuccess = function (e) {
var result = e.target.result;
if (result) {
// ...
} else {
// ...
}
}

参考文章

作者链接
阮一峰https://www.ruanyifeng.com/blog/2018/07/indexeddb.html